home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-03-30 | 5.7 KB | 130 lines | [TEXT/CCL2] |
- ;;;-*-Mode: LISP; Package: CCL -*-
- ;from l1-clos.lisp
- ; Copyright (C) 1990 Apple Computer, Inc. All rights reserved.
-
- ; Gives a better error message when a generic function is called, no
- ; method is applicable, and an error is signalled. The error message
- ; attempts to identify the problem as a specific argument being of the
- ; wrong type.
-
-
- (in-package :ccl)
-
- (defmethod no-applicable-method (gf &rest args)
- ;(error "No applicable method for args:~% ~s~% to ~s" args gf)
- (%error (make-condition 'no-applicable-method :generic-function gf :arguments args) '()
- ;; Go past the anonymous frame to the frame for the caller of the generic function
- (parent-frame (%get-frame-ptr))))
-
- (define-condition no-applicable-method (error)
- ((generic-function :initarg :generic-function)
- (arguments :initarg :arguments))
- (:report (lambda (condition stream)
- (labels ((satisfies (argument specializer)
- (if (consp specializer)
- (eql argument (second specializer))
- (typep argument specializer)))
- (comma (conjunction more all)
- (when more
- (when (cddr all) (write-string "," stream))
- (unless (cdr more)
- (write-string " " stream)
- (write-string conjunction stream))
- (write-string " " stream)))
- (print-type (type)
- (prin1 (or (and (classp type) (class-name type)) type) stream)))
- (with-slots (generic-function arguments) condition
- (format stream "No applicable method for ~S."
- (or (function-name generic-function) generic-function))
- (let* ((methods (generic-function-methods generic-function))
- (n-required (function-args generic-function))
- (matches (make-list n-required :initial-element nil))
- (t-class (find-class t)))
- ;; Find argument positions with no matching methods
- (dolist (method methods)
- (loop for specializer in (method-specializers method)
- and argno from 0
- and arg in arguments do
- (when (satisfies arg specializer)
- (setf (elt matches argno) t))))
- (if (some #'null matches)
- ;; Report the specializers of methods for argument positions that did not match
- (loop for argno from 0
- and arg in arguments
- and match in matches do
- (unless match
- (format stream "~%The ~:R argument, ~S, was of the wrong type." (1+ argno) arg)
- (let ((types (loop for method in methods
- as specializers = (method-specializers method)
- when (loop for specializer in specializers
- and method-argno from 0
- and arg in arguments
- always (or (not (elt matches method-argno))
- (satisfies arg specializer)))
- collect (elt specializers argno))))
- (when types
- (format stream "~%An argument of type ")
- (loop for (type . more) on types do
- (print-type type)
- (comma "or" more types))
- (write-string " was expected." stream)))))
- ;; No single argument position is at fault
- ;; Report the available argument type combinations
- (let ((specialized nil))
- (dolist (method methods)
- (loop for specializer in (method-specializers method)
- and argno from 0 do
- (unless (eq specializer t-class)
- (pushnew argno specialized))))
- (setq specialized (nreverse specialized))
- (format stream "~%The ")
- (loop for (argno . more) on specialized do
- (format stream "~:R" (1+ argno))
- (comma "and" more specialized))
- (format stream " arguments, ")
- (loop for (argno . more) on specialized do
- (format stream "~S" (elt arguments argno))
- (comma "and" more specialized))
- (format stream ", were of the wrong type.~%Acceptable combinations of types are:")
- (dolist (method methods)
- (format stream "~% ")
- (loop for (argno . more) on specialized
- as type = (elt (method-specializers method) argno) do
- (print-type type)
- (comma "and" more specialized)))))))))))
-
- #||
-
- ;;; Test cases
-
- (defun tst (x y) (print (f1 x y)))
-
- (defclass c1 () ())
- (defclass c2 () ())
- (defclass c3 () ())
- (defclass c4 (c1) ())
- (defvar c1 (make-instance 'c1))
- (defvar c2 (make-instance 'c2))
- (defvar c3 (make-instance 'c3))
- (defvar c4 (make-instance 'c4))
-
- (defmethod f1 ((self c1) (x integer)) 1)
-
- (tst c1 t)
- (tst c2 t)
- (tst c2 0)
-
- (defmethod f1 ((self c1) (x float)) 2)
-
- (tst c1 t)
-
- (defmethod f1 ((self c1) (x c2)) 2)
-
- (tst c1 t)
-
- (defmethod f1 ((self c2) (x symbol)) 2)
-
- (tst c1 t)
-
- ||#
-